//
// Created by suhuamo on 2025/6/22.
//

#ifndef LOGGER_H
#define LOGGER_H

#include<queue>
#include<string>
#include<mutex>
#include<condition_variable>
#include<thread>
#include<atomic>
#include<fstream>
#include<sstream>
#include<vector>
#include<stdexcept>

// 辅助函数，用于将单个参数转换为字符串
template<typename T>
std::string to_string_helper(T&& arg) {
    std::ostringstream oss;
    oss << std::forward<T>(arg);
    return oss.str();
}

// 线程安全的日志队列
class LogQueue {
public:
    void push(const std::string& msg);
    bool pop(std::string& msg);
    void shutdown();
private:
    std::queue<std::string> queue_;
    std::mutex mutex_;
    std::condition_variable cond_;
    bool is_shutdown_ = false;
};

enum class LogLevel {
    DEBUG, INFO, WARN, ERROR
};

class Logger {
public:
    explicit Logger(const std::string& filename);
    ~Logger();
    // 日志接口，支持带格式字符串日志
    template<typename... Args>
    void log(const LogLevel level, const std::string& format, Args&&... arg) {
        std::string level_str;
        switch (level) {
            case LogLevel::DEBUG:
                level_str = "[DEBUG] ";
                break;
            case LogLevel::INFO:
                level_str = "[INFO] ";
                break;
            case LogLevel::WARN:
                level_str = "[WARN] ";
                break;
            case LogLevel::ERROR:
                level_str = "[ERROR] ";
                break;
        }
        log_queue_.push(level_str + "[" + getCurrentTime() + "] "+  formatMessage(format, std::forward<Args>(arg)...));
    }
private:
    LogQueue log_queue_;
    // todo：后续使用线程池优化
    std::thread worker_thread_;
    std::ofstream log_file_;
    std::atomic<bool> exit_flag_;

    std::string getCurrentTime();

    template<typename... Args>
    std::string formatMessage(const std::string& format, Args&&... args) {
        const std::vector<std::string> arg_strings = {to_string_helper(std::forward<Args>(args))...};
        std::ostringstream oss;
        size_t arg_index = 0;
        size_t pos = 0;
        // 从 pos 下标开始，找到下一个 {} 符号的 { 字符的下标
        size_t placeholder = format.find("{}", pos);

        // 进行 {} 符号的替换操作
        while (placeholder != std::string::npos) {
            oss << format.substr(pos, placeholder - pos);
            if (arg_index < arg_strings.size()) {
                oss << arg_strings[arg_index++];
            } else {
                // todo: 可以优化，直接将format后续的文本写入oss，然后return即可
                oss << "{}";
            }
            // 跳过 {} 符号
            pos = placeholder + 2;
            placeholder = format.find("{}", pos);
        }
        // 将剩余的文本写入oss,即最后一个 {} 后面的所有文本
        oss << format.substr(pos);

        // 如果 {} 写少了，那么将多余的参数直接转换为文本写入 oss
        while (arg_index < arg_strings.size()) {
            oss << arg_strings[arg_index++];
        }

        return oss.str();
    }
};



#endif //LOGGER_H
